﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MethodWorx.CMS.TemplateLanguage;
using MethodWorx.CMS.Content;
using MethodWorx.CMS.Services;
using MethodWorx.CMS.Providers;
using MethodWorx.CMS.Plugins.ContentTree;
using System.Web.Mvc;
using MethodWorx.CMS.Plugins.ActionResults;
using System.Web;

namespace MethodWorx.CMS.Plugins.AssetManagement
{
    internal static class DictionaryExtensions
    {
        internal static bool ContextKeyCaseInsensitive(this Dictionary<string, Guid> src, string key)
        {
            return src.Keys.Where(k => k.ToLower() == key.ToLower()).Any();
        }

        internal static Guid GetValue(this Dictionary<string, Guid> src, string key)
        {
            return src.Where(k => k.Key.ToLower() == key.ToLower()).First().Value;
        }
    }

    public class AssetManagementExtension : IRequestPlugin, IIdePlugin, IContentTreePlugin
    {
        //private PluginService service;
        //private SchemaService schema;
        private ICmsDataProvider provider;

        public AssetManagementExtension()
        {
        }

        public Guid Id { get { return  GetPluginId(); } }

        public static Guid GetPluginId()
        {
            return new Guid("{1C57C554-F6D1-4B1D-9958-DA9893631112}");
        }

        private IdeExtension assetFolderIdeExtensions = new IdeExtension()
        {
            Id = new Guid("{33B1B1B1-A6D9-49A4-87C8-051AA01DBC4D}"),
            DisplayName = "Assets",
            Name = "Asset Folder Management",
            WebEditor = new AssemblyResourceReference(typeof(AssetManagementExtension).Assembly, "Plugins/Views/AssetManagement/AddAssetFolder.ascx"),
            Controller = typeof(AssetFolderManagement)
        };

        public IEnumerable<IdeExtension> GetIdeExtensionsForPageTemplate(PageTemplate template)
        {
            return null;
        }

        public IEnumerable<IdeExtension> GetIdeExtensionsForPage(Page page)
        {
            return null;
        }


        public IEnumerable<IdeExtension> GetIdeExtensions()
        {
            yield return assetFolderIdeExtensions;
        }

        public string Name
        {
            get { return "Asset Management"; }
        }

        public string Description
        {
            get { return "Allows user uploaded assets"; }
        }

        public static string GetVirtualPath(string url)
        {
            if (HttpContext.Current.Request.ApplicationPath == "/")
            {
                return "~" + url;
            }

            return Regex.Replace(url, "^" +
                           HttpContext.Current.Request.ApplicationPath + "(.+)$", "~$1");
        }

        

        public bool ProcessRequest(HttpContextBase context)
        {
            PluginService service = new PluginService(this.provider);
            AssetManagementService assets = new AssetManagementService(this.provider);

            var assetFolder = assets.GetAssetFolder(GetVirtualPath(context.Request.Url.AbsolutePath).TrimStart('~'));
            if (assetFolder != null)
            {
                //
                //  ok, this is the page template, now get the asset
                var map = service.GetUserData<AssetMap>(this, assetFolder, "AssetMap");
                if (map != null && map.Map.ContextKeyCaseInsensitive(context.Request.Url.AbsolutePath.Split('/').Last().ToLower()))
                {
                    //  get the user data
                    var asset = service.GetUserData<Asset>(map.Map.GetValue(context.Request.Url.AbsolutePath.Split('/').Last().ToLower()));

                    context.Response.Clear();
                    context.Response.ContentType = asset.MimeType;
                    context.Response.BinaryWrite(asset.Data);
                    return true;
                }
            }
            return false;
        }

        #region IRequestPlugin Members

        private const string TEMPLATES = "{A342349A-36E4-4254-B532-9EA0D3D07D49}";
        
        public IEnumerable<VirtualUrl> GetVirtualUrls(string filter, string contextType, string contextId)
        {
            SchemaService schema = new SchemaService(this.provider);
            AssetManagementService assets = new AssetManagementService(this.provider);

            PluginService service = new PluginService(this.provider);

            if (string.IsNullOrEmpty(contextType) && string.IsNullOrEmpty(contextId))
            {
                //  we want any context urls at the "site level"
                //  this would mean we want "Templates"
                foreach (var assetFolder in assets.GetRootAssetFolder().Children ?? new AssetFolder[] { })
                {
                    yield return new VirtualUrl()
                    {
                        Id = assetFolder.Id.ToString(),
                        Name = assetFolder.Name,
                        Path = "/" + assetFolder.Name,
                        Type = "AssetFolder",
                        IsFolder = true
                    };
                }
                foreach (var asset in assets.GetAssets(Guid.Empty))
                {
                    yield return new VirtualUrl()
                    {
                        Id = asset.Id.ToString(),
                        Name = asset.UserData.Name,
                        Path = "/" + asset.UserData.Name,
                        Type = "Asset",
                        IsFolder = false
                    };
                }
            }
            else if (contextType == "AssetFolder" && !string.IsNullOrEmpty(contextId))
            {
                var assetFolder = assets.GetAssetFolder(Guid.Parse(contextId));
                var path = assets.GetPath(assetFolder, false);

                foreach (var asset in assets.GetAssets(Guid.Parse(contextId)))
                {
                    yield return new VirtualUrl()
                    {
                        Id = asset.Id.ToString(),
                        Name = asset.UserData.Name,
                        Path = path + "/" + asset.UserData.Name,
                        Type = "Asset",
                        IsFolder = false
                    };
                }

                foreach(var folder in assets.GetAssetFolder(Guid.Parse(contextId)).Children)
                {
                    yield return new VirtualUrl()
                    {
                        Id = folder.Id.ToString(),
                        Name = folder.Name,
                        Path = path + "/" + folder.Name,
                        Type = "AssetFolder",
                        IsFolder = true
                    };
                }
            }
           
        }

        public void SetProvider(ICmsDataProvider provider)
        {
            this.provider = provider;
        }

        #endregion

        public IEnumerable<TreeNode> GetTreeNodes(string objectType, Guid? objectId)
        {
            PluginService service = new PluginService(this.provider);
            AssetManagementService assets = new AssetManagementService(this.provider);
            //
            //  ok, we want to extend the tree by adding a new node on the top
            //  level called "Assets"
            if (string.IsNullOrEmpty(objectType) && objectId == null)
            {
                //
                //  ok, this is the root
                return new TreeNode[]
                {
                    new TreeNode()
                    { 
                        Title = "Assets",
                        ObjectType = "Assets",
                        Icon = "~/Images/icons/images.png",
                        ObjectId = Guid.Empty,
                        ToolbarButtons = GetToolbarButtons(null),
                        MenuItems = GetMenuItems(false)
                    }
                };
            }
            else if(objectType == "Assets")
            {
                var assetFolder = service.GetUserData<AssetFolder>(this, null, "AssetFolder");
                if(assetFolder != null)
                {
                    //
                    //  ok, here we go
                    List<TreeNode> nodes = new List<TreeNode>();

                    foreach (var folder in assetFolder.GetChildren(objectId) ?? new AssetFolder [0])
                    {
                        nodes.Add(new TreeNode()
                        {
                            Title = folder.Name,
                            ObjectType = "Assets",
                            ObjectId = folder.Id,
                            Icon = "~/Images/icons/folder.png",
                            ToolbarButtons = GetToolbarButtons(folder),
                            DefaultAction = "ManageAssets",
                            MenuItems = GetMenuItems(true)
                        });
                    }

                    foreach (var asset in assets.GetAssets(objectId ?? Guid.Empty))
                    {
                        nodes.Add(new TreeNode()
                        {
                            Title = asset.UserData.Name,
                            ObjectType = "Asset",
                            ObjectId = asset.Id,
                            Icon = "~/Images/icons/image.png",
                            //ToolbarButtons = GetToolbarButtons()
                        });
                    }


                    return nodes.ToArray();
                }
            }
            
            return new TreeNode[0];
        }

        private TreeNodeMenuItem[] GetMenuItems(bool folder)
        {
            var items = new List<TreeNodeMenuItem>();

            items.Add(
                new TreeNodeMenuItem()
                {
                    Action = "ManageAssets",
                    Id = "ManageAssets",
                    Title = "Manage Assets"
                });

            items.Add(
              new TreeNodeMenuItem()
              {
                  Action = "UploadAsset",
                  Id = "UploadAsset",
                  Title = "Upload Asset"
              });

            items.Add(
              new TreeNodeMenuItem()
              {
                  Action = "UploadZip",
                  Id = "UploadZip",
                  Title = "Upload Zip"
              });

            items.Add(
                new TreeNodeMenuItem()
                {
                    Action = "CreateAssetFolder",
                    Id = "CreateAssetFolder",
                    Title = "Create Folder"
                });



            if (folder)
            {
                items.Add(new TreeNodeMenuItem()
                {
                    Action = "RenameAssetFolder",
                    Id = "RenameAssetFolder",
                    Title = "Rename"
                });

                items.Add(
             new TreeNodeMenuItem()
             {
                 Action = "DeleteAssetFolder",
                 Id = "DeleteAssetFolder",
                 Confirm = "Are you sure you want to delete this folder?",
                 Title = "Delete"
             });
            }

            return items.ToArray();
        }

        private ToolbarButton[] GetToolbarButtons(AssetFolder folder)
        {
            AssetManagementService assets = new AssetManagementService(this.provider);
            string path = "/ROOT";
            if (folder != null)
                path = assets.GetPath(folder);
            return new ToolbarButton[]
            {
                new ToolbarButton()
                {
                    Id = "CreateAssetFolder",
                    Icon = "~/Images/Icons/folder_add.png",
                    Title = "Create Folder",
                },
                new ToolbarButton()
                {
                    Id = "ManageAssets",
                    Icon = "~/Images/Icons/image_edit.png",
                    Title = "Manage Assets",
                    ContextText = "Assets: " + path
                },
            };
        }

        public ActionResult InvokeAction(string action, string objectType, Guid? objectId)
        {
            switch (action)
            {
                case "CreateAssetFolder":
                    return new OpenDialogResult(PluginUrlHelper.GlobalPluginAction(this.assetFolderIdeExtensions, "Add") + "?assetFolderId=" + objectId, "Create Folder");
                    break;
                case "ManageAssets":
                    return new TabResult("Assets", PluginUrlHelper.GlobalPluginAction(this.assetFolderIdeExtensions, "Manage") + "?instance=" + objectId);
                    break;
                case "RenameAssetFolder":
                    return new RenameTreeNodeResult(PluginUrlHelper.GlobalPluginAction(this.assetFolderIdeExtensions, "RenameFolder") + "?instance=" + objectId);
                    break;
                case "UploadAsset":
                    return new OpenDialogResult(PluginUrlHelper.GlobalPluginAction(this.assetFolderIdeExtensions, "AddAsset") + "?instance=" + objectId + "&fromTree=true", "Upload Asset");
                    break;
                case "UploadZip":
                    return new OpenDialogResult(PluginUrlHelper.GlobalPluginAction(this.assetFolderIdeExtensions, "AddAsset") + "?instance=" + objectId + "&fromZip=true&fromTree=true", "Upload Assets From Zip");
                    break;
                case "DeleteAssetFolder":
                    var service = new AssetManagementService(this.provider);
                    service.DeleteAssetFolder(objectId.Value);
                    return new RefreshTreeNodeResult(true);
                    break;
                default:
                    return new EmptyResult();
                    break;
            }

            
        }
    }
}
